package badugaserver;
import java.io.IOException;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;

/**
 * @author Wojtek N., Kamil M.
 * @version 0.7
 * The listener for the server.
 */
public class Listener
{
	private static int allPlayers;
	private static int startingTokens;
	private static int smallBlind;
	private static int bigBlind;
	private static Table table;
	private static ServerSocket server;
	private static int playerID = 0;
	private static boolean doesTableRunning = false;
	private static WorkerRunnable[] sharedWorker;

	/**
	 * Constructor of the class Listener.
	 */
	public Listener(int allPlayers, int startingTokens, int smallBlind, int bigBlind)
	{
		this.allPlayers = allPlayers;
		this.startingTokens = startingTokens;
		this.smallBlind = smallBlind;
		this.bigBlind = bigBlind;
		this.server = Server.server;
		table = new Table(allPlayers, smallBlind, bigBlind);
		try
		{
			start();
		}
		catch(BadugaExceptions be)
		{
			System.err.println(be.getMessage());
		}
	}
	
	/**
	 * Prints string on server console.
	 */
	private void serverPrint(String s)
	{
		System.out.println(s);
	}
	
	/**
	 * Method which checks if everybody are online.
	 */
	private void doPlayersConnected()
	{
		for (int i=0; i<sharedWorker.length; i++) 
		{
			if (sharedWorker[i]!=null && !sharedWorker[i].isAlive()) 
			{
				sharedWorker[i] = null;
				playerID--;
				if (playerID < 0) 
				{
					playerID = 0;
				}
				serverPrint("Player " + i + " disconnected.");
			}
		}
	}
	
	/**
	 * Method which search for first empty slot for player.
	 */
	private int checkForFreeSpot()
	{
		for (int i=0; i<sharedWorker.length; i++) 
		{
			if (sharedWorker[i] == null) 
			{
				return i;
			}
		}
		return -1;
	}
	
	/**
	 * Method in which player gets connection.
	 */
	private void connectClient(int spot, Socket client) throws IOException
	{
		if(spot == -1)
		{
			serverPrint("Client tries to connect to the server.");
			PrintWriter outToClient = new PrintWriter(client.getOutputStream(), true);
			sharedWorker[playerID] = new WorkerRunnable(allPlayers, startingTokens, smallBlind, bigBlind, client, outToClient, playerID, sharedWorker);
			outToClient.println(allPlayers + "INI__" + playerID + allPlayers + startingTokens + bigBlind + smallBlind);
			sharedWorker[playerID].start();
			playerID++;
		}
		else
		{
			synchronized(server)
			{
				serverPrint("Client tries to connect to the server.");
				PrintWriter outToClient = new PrintWriter(client.getOutputStream(), true);
				sharedWorker[spot] = new WorkerRunnable(allPlayers, startingTokens, smallBlind, bigBlind, client, outToClient, playerID, sharedWorker);
				outToClient.println(allPlayers + "INI__" + playerID + allPlayers + startingTokens + bigBlind + smallBlind);
				sharedWorker[spot].start();
				playerID++;
			}
		}
	}
	
	/**
	 * Method which listen to and wait for clients. 
	 * Client will join table only if there is a free space for him.
	 */
	private void start() throws BadugaExceptions
	{
		sharedWorker = new WorkerRunnable[allPlayers];
		try
		{
			while (true) 
			{
				Socket client = server.accept();
				doPlayersConnected();
				
				if (playerID<allPlayers) 
				{
					if (!doesTableRunning) 
					{
						connectClient(-1, client);
						if (playerID == allPlayers) 
						{
							table.setSharedWorker(sharedWorker);
							doesTableRunning = true;
							table.start();
						}
					}
					else 
					{
						int freeSpot = checkForFreeSpot();
					
						synchronized (server) 
						{
							connectClient(freeSpot, client);
						}
						
						if (!table.isAlive())
						{
							if (playerID == allPlayers) 
							{
								serverPrint("Server: New Table is needed.");
								table = new Table(allPlayers, smallBlind, bigBlind);
								table.setSharedWorker(sharedWorker);
								doesTableRunning = true;
								table.start();
							}
						}
					}

				}
				else 
				{
					PrintWriter outToClient = new PrintWriter(client.getOutputStream(), true);
					serverPrint("Table is for " + allPlayers + " players. Sorry, but we are full. Try again later.");
					outToClient.close();
					client.close();
				}
			}
		} 
		catch (IOException ioe) 
		{
			System.err.println("Client accept failed on " + Server.port);
		}	
	}
	
	
	
}